package com.ape.mapsa.produccion.dao;

import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository("genericDao")
public abstract class GenericDAOImpl<T, PK extends java.io.Serializable> implements GenericDAO<T, PK> {

	private static final Logger logger = Logger.getLogger(GenericDAOImpl.class);

	@Autowired
	protected SessionFactory sessionFactory; // comes in from bean

	private Class<T> entityClass;

	// constructors
	@SuppressWarnings("unchecked")
	public GenericDAOImpl() {
		this.entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	// getters and setters
	public SessionFactory getSessionFactory() {
		logger.info("Autowiring Session Factory");
		if (sessionFactory == null)
			throw new IllegalStateException("SessionFactory has not been set on DAO before usage");
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public Class<T> getEntityClass() {
		return entityClass;
	}

	public void setEntityClass(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

	/**
	 * Loads the row using session load method. <BR>
	 * this may throw exception if the row is not present
	 */
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	public T findById(PK id) {
		Session openSession = sessionFactory.getCurrentSession();
		T entity = (T) openSession.load(getEntityClass(), id);
		return entity;
	}

	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	public T getById(Long id) {
		Session session = sessionFactory.getCurrentSession();
		T entity = (T) session.get(getEntityClass(), id);
		return entity;
	}

	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	public List<T> findByExample(T exampleInstance, String... excludeProperty) {
		Session session = sessionFactory.getCurrentSession();
		Criteria crit = session.createCriteria(getEntityClass());
		Example example = Example.create(exampleInstance);
		for (String exclude : excludeProperty) {
			example.excludeProperty(exclude);
		}
		crit.add(example);
		List<T> critList = crit.list();
		return critList;
	}

	public T save(T entity) {
		Session session = sessionFactory.getCurrentSession();
		session.save(entity);
		return entity;
	}

	public void update(T entity) {
		Session session = sessionFactory.getCurrentSession();
		session.update(entity);
	}

	public void delete(T entity) {
		Session session = sessionFactory.getCurrentSession();
		session.delete(entity);
	}

	@Override
	@Transactional(readOnly = true)
	public List<T> getAll() {
		Session session = sessionFactory.getCurrentSession();
		final Criteria crit = session.createCriteria(entityClass);
		List<T> criteria = crit.list();
		return criteria;
	}

}